#include "kc031service.h"

#ifdef USE_LUA

//你需要include这几个lua头文件
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

#ifdef __cplusplus
}
#endif

#include "aexgpio.h"
#include "aexudp.h"
#include "kc031service.h"

lua_State *L=NULL;

/**
 * @brief 调用LUA的脚本函数，当输入引脚改变后如果配置了LUA脚本，则调用脚本里的oninput函数
 * 
 * @param index 	改变的引脚序号
 * @param level 	引脚的电平0/1
 * @return int 		返回值
 */
int lua_oninput(lua_State *L,int index,int level)
{
	int ret = -1;
	/*函数名*/
	lua_getglobal(L, "oninput");
	/*参数入栈*/
	lua_pushnumber(L, index);
	/*参数入栈*/
	lua_pushnumber(L, level);
	/*开始调用函数，有2个参数，1个返回值*/
	//lua_call(L, 2, 1);
	if(lua_pcall(L, 2, 1, 0)){
		psus_error(lua_tostring(L, -1));
		lua_pop(L,-1); 
	}else{
		/*取出返回值*/
		ret = (int)lua_tonumber(L, -1);
		/*清除返回值的栈*/
		lua_pop(L, 1);
	}
	if(ret <=  0){
		aexudp_oninput(index,level);
	}
	return ret;
}

/**
 * @brief 
 * 
 * @param p1 	
 * @param p2 	
 * @return int 		返回值
 */
int lua_do_func(lua_State *L,char *func,int p1,int p2)
{
	int ret = -1;
	/*函数名*/
	lua_getglobal(L, func);
	/*参数入栈*/
	lua_pushnumber(L, p1);
	/*参数入栈*/
	lua_pushnumber(L, p2);
	/*开始调用函数，有2个参数，1个返回值*/
	//lua_call(L, 2, 1);
	if(lua_pcall(L, 2, 1, 0)){
		psus_error("Exec %s error:%s",func,lua_tostring(L, -1));
		lua_pop(L,-1); 
		aexudp_do_func_rsp(func,-1);
	}else{
		/*取出返回值*/
		ret = (int)lua_tonumber(L, -1);
		/*清除返回值的栈*/
		lua_pop(L, 1);
		aexudp_do_func_rsp(func,ret);
	}
	return ret;
}

/*
	为LUA提供的移位函数，左移函数
*/
static int do_lshift(lua_State *L)
{
	int value = luaL_checknumber(L,1);		//获取并检查第一个参数是否为数字
	int index = luaL_checknumber(L,2);		//获取并检查第二个参数是否为数字

	lua_pushnumber(L,value<<index);
	return 1;
}

/*
	为lua提供右移函数
*/
static int do_rshift(lua_State *L)
{
	int value = luaL_checknumber(L,1);		//获取并检查第一个参数是否为数字
	int index = luaL_checknumber(L,2);		//获取并检查第二个参数是否为数字

	lua_pushnumber(L,value>>index);
	return 1;
}

/*
	为lua提供and函数
*/
static int do_and(lua_State *L)
{
	int value = luaL_checknumber(L,1);		//获取并检查第一个参数是否为数字
	int index = luaL_checknumber(L,2);		//获取并检查第二个参数是否为数字

	lua_pushnumber(L,value&index);
	return 1;
}

/*
	为lua提供or函数
*/
static int do_or(lua_State *L)
{
	int value = luaL_checknumber(L,1);		//获取并检查第一个参数是否为数字
	int index = luaL_checknumber(L,2);		//获取并检查第二个参数是否为数字

	lua_pushnumber(L,value|index);
	return 1;
}

static int do_dout_cmd(lua_State *L)
{
	int cmd = luaL_checknumber(L,1);		//获取并检查第一个参数是否为数字
	int addr = luaL_checknumber(L,2);		//获取并检查第二个参数是否为数字
	int value = luaL_checknumber(L,3);		//输出的值
	int mask = luaL_checknumber(L,4);		//需要操作的输出口，使用掩码
	int delay = luaL_checknumber(L,5);		//延时时间单位毫秒，0表示即时执行
	
	psus_hint("cmd:%02X,v=%04X,m=%04X,d=%d",cmd,value,mask,delay);
	if(delay > 0){
		if(fok_for_timer(delay,0) == 0){
			//使用子进程延迟执行
			aexgpio_set_out(mask,value);
			aexudp_report_iostatus(cmd);
			exit_for_fok();		//执行完延迟任务退出子进程
		}
	}else{
		//立即执行
		aexgpio_set_out(mask,value);
		aexudp_report_iostatus(cmd);
	}

	return 1;// 返回结果的个数
}

static int do_udp_cmd(lua_State *L)
{
	return do_dout_cmd(L);
}

static int do_dout_one_cmd(lua_State *L)
{
	int cmd = luaL_checknumber(L,1);		//获取并检查第一个参数是否为数字
	int addr = luaL_checknumber(L,2);		//获取并检查第二个参数是否为数字
	int index = luaL_checknumber(L,3);		//index
	int level = luaL_checknumber(L,4);		//level
	int delay = luaL_checknumber(L,5);		//延时时间单位毫秒，0表示即时执行
	
	psus_hint("cmd:%02X,i=%04X,l=%04X,d=%d",cmd,index,level,delay);
	if(delay > 0){
		if(fok_for_timer(delay,0) == 0){
			//使用子进程延迟执行
			aexgpio_set_out_by_index(index,level);
			aexudp_report_iostatus(cmd);
			exit_for_fok();		//执行完延迟任务退出子进程
		}
	}else{
		//立即执行
		aexgpio_set_out_by_index(index,level);
		aexudp_report_iostatus(cmd);
	}

	return 1;// 返回结果的个数
}

static int do_report_iostatus(lua_State *L)
{
	aexudp_report_iostatus(AEX_CMD_IOSTATUS);
	return 1;// 返回结果的个数
}

static int do_log(lua_State *L)
{
	const char *msg = luaL_checkstring (L, 1);
	
	psus_hint("%s",msg);

	return 1;// 返回结果的个数
}

/**
 * @brief 当输入改变时使用该函数调用LUA脚本
 * 
 * @param luafile 
 * @param index 
 * @param level 
 * @return int 
 */
int lua_exec(char *luafile,int value,int old)
{
	int ret=-1,index,level;

	if(fok_for_timer(0,0) == 0){
		//使用子进程
		// psus_hint("%s:%d",__func__,__LINE__);
		// lua_State *L = lua_newstate(NULL,NULL); /* 创建lua状态机 */
		lua_State *L = luaL_newstate(); /* 创建lua状态机 */
		// psus_hint("%s:%d",__func__,__LINE__);
		if(L != NULL){
			luaopen_base(L);
			// psus_hint("%s:%d",__func__,__LINE__);
			luaopen_table(L);
			// psus_hint("%s:%d",__func__,__LINE__);
			luaopen_string(L);
			// psus_hint("%s:%d",__func__,__LINE__);
			luaL_openlibs(L);	 /* 打开Lua状态机中所有Lua标准库 */
			lua_register(L, "do_lshift", do_lshift);//注册C函数到lua
			lua_register(L, "do_rshift", do_rshift);//注册C函数到lua
			lua_register(L, "do_and", do_and);//注册C函数到lua
			lua_register(L, "do_or", do_or);//注册C函数到lua
			lua_register(L, "do_udp_cmd", do_udp_cmd);//注册C函数到lua
			lua_register(L, "do_dout_cmd", do_dout_cmd);//注册C函数到lua
			lua_register(L, "do_dout_one_cmd", do_dout_one_cmd);//注册C函数到lua
			lua_register(L, "do_report_iostatus", do_report_iostatus);//注册C函数到lua
			lua_register(L, "do_log", do_log);//注册C函数到lua
			/*加载lua脚本*/
			// psus_hint("%s:%d",__func__,__LINE__);
			if(luaL_loadfile(L, luafile) == 0){
				lua_pcall(L,0,0,0);
				//需要判断value和old的每一位是否相同
				for(index=AEXIN_MIN_INDEX;index<=AEXIN_MAX_INDEX;index++){
					int mask = 1<<index;
					if((value&mask) != (old&mask)){
						// psus_hint("%s:%d",__func__,__LINE__);
						//aexudp_oninput(index-AEXIN_MIN_INDEX, (value&mask)>0?1:0);
						ret = lua_oninput(L,index-AEXIN_MIN_INDEX, (value&mask)>0?1:0);
						psus_hint("oninput(%d,%d) %d ",index,(value&mask)>0?1:0,ret);
					}
				}
			}else{
				psus_error("lua load  file error.");
			}
			/*清除Lua*/
			lua_close(L);
			L = NULL;
		}
		exit_for_fok();		//执行完延迟任务退出子进程
	}
	return ret;
}

int lua_exec_one(char *luafile,int index,int level)
{
	int ret=-1;

	if(fok_for_timer(0,0) == 0){
		//使用子进程
		// lua_State *L = lua_newstate(NULL,NULL); /* 创建lua状态机 */
		lua_State *L = luaL_newstate(); /* 创建lua状态机 */
		if(L != NULL){
			luaopen_base(L);
			luaopen_table(L);
			luaopen_string(L);

			luaL_openlibs(L);	 /* 打开Lua状态机中所有Lua标准库 */
			lua_register(L, "do_lshift", do_lshift);//注册C函数到lua
			lua_register(L, "do_rshift", do_rshift);//注册C函数到lua
			lua_register(L, "do_and", do_and);//注册C函数到lua
			lua_register(L, "do_or", do_or);//注册C函数到lua
			lua_register(L, "do_udp_cmd", do_udp_cmd);//注册C函数到lua
			lua_register(L, "do_dout_cmd", do_dout_cmd);//注册C函数到lua
			lua_register(L, "do_dout_one_cmd", do_dout_one_cmd);//注册C函数到lua
			lua_register(L, "do_report_iostatus", do_report_iostatus);//注册C函数到lua
			lua_register(L, "do_log", do_log);//注册C函数到lua
			/*加载lua脚本*/
			if(luaL_loadfile(L, luafile) == 0){
				lua_pcall(L,0,0,0);
				ret = lua_oninput(L,index, level);
				psus_hint("oninput(%d,%d) %d ",index,level,ret);
			}else{
				psus_error("lua load file error.");
			}
			/*清除Lua*/
			lua_close(L);
			L = NULL;
		}
		exit_for_fok();		//执行完延迟任务退出子进程
	}
	return ret;
}

int lua_on_recv_from_uart(char *luafile,char *buf,int len)
{
	int ret=-1,index,level;

	if(fok_for_timer(0,0) == 0){
		//使用子进程
		// lua_State *L = lua_newstate(NULL,NULL); /* 创建lua状态机 */
		lua_State *L = luaL_newstate(); /* 创建lua状态机 */
		if(L != NULL){
			luaopen_base(L);
			luaopen_table(L);
			luaopen_string(L);
			luaL_openlibs(L);	 /* 打开Lua状态机中所有Lua标准库 */
			lua_register(L, "do_lshift", do_lshift);//注册C函数到lua
			lua_register(L, "do_rshift", do_rshift);//注册C函数到lua
			lua_register(L, "do_and", do_and);//注册C函数到lua
			lua_register(L, "do_or", do_or);//注册C函数到lua
			lua_register(L, "do_udp_cmd", do_udp_cmd);//注册C函数到lua
			lua_register(L, "do_dout_cmd", do_dout_cmd);//注册C函数到lua
			lua_register(L, "do_dout_one_cmd", do_dout_one_cmd);//注册C函数到lua
			lua_register(L, "do_report_iostatus", do_report_iostatus);//注册C函数到lua
			lua_register(L, "do_log", do_log);//注册C函数到lua
			/*加载lua脚本*/
			if(luaL_loadfile(L, luafile) == 0){
				lua_pcall(L,0,0,0);
				/*函数名*/
				lua_getglobal(L, "on_recv_from_uart");
				/*参数入栈*/
				lua_pushstring(L, buf);
				/*参数入栈*/
				lua_pushnumber(L, len);
				/*开始调用函数，有2个参数，1个返回值*/
				if(lua_pcall(L, 2, 1, 0)){
					psus_error(lua_tostring(L, -1));
					lua_pop(L,-1); 
				}else{
					/*取出返回值*/
					ret = (int)lua_tonumber(L, -1);
					/*清除返回值的栈*/
					lua_pop(L, 1);
				}
			}else{
				psus_error("lua load  file error.");
			}
			/*清除Lua*/
			lua_close(L);
			L = NULL;
		}
		exit_for_fok();		//执行完延迟任务退出子进程
	}
	return ret;
}


int lua_exec_userfunc(char *luafile,char *func,int p1,int p2)
{
	int ret=-1;

	if(fok_for_timer(0,0) == 0){
		//使用子进程
		// lua_State *L = lua_newstate(NULL,NULL); /* 创建lua状态机 */
		lua_State *L = luaL_newstate(); /* 创建lua状态机 */
		if(L != NULL){
			luaopen_base(L);
			luaopen_table(L);
			luaopen_string(L);

			luaL_openlibs(L);	 /* 打开Lua状态机中所有Lua标准库 */
			lua_register(L, "do_lshift", do_lshift);//注册C函数到lua
			lua_register(L, "do_rshift", do_rshift);//注册C函数到lua
			lua_register(L, "do_and", do_and);//注册C函数到lua
			lua_register(L, "do_or", do_or);//注册C函数到lua
			lua_register(L, "do_udp_cmd", do_udp_cmd);//注册C函数到lua
			lua_register(L, "do_dout_cmd", do_dout_cmd);//注册C函数到lua
			lua_register(L, "do_dout_one_cmd", do_dout_one_cmd);//注册C函数到lua
			lua_register(L, "do_report_iostatus", do_report_iostatus);//注册C函数到lua
			lua_register(L, "do_log", do_log);//注册C函数到lua
			/*加载lua脚本*/
			if(luaL_loadfile(L, luafile) == 0){
				//psus_hint("---%s(%d,%d)",func!=NULL?func:"",p1,p2);
				lua_pcall(L,0,0,0);
				ret = lua_do_func(L,func,p1,p2);
				psus_hint("Lua execute %s(%d,%d) return %d ",func,p1,p2,ret);
			}else{
				psus_error("lua load file %s error.",luafile);
			}
			/*清除Lua*/
			lua_close(L);
			L = NULL;
		}
		exit_for_fok();		//执行完延迟任务退出子进程
	}
	return ret;
}

#endif